using System;
using System.Net;
using System.Security.Cryptography;

namespace ProtoScratch.Common
{
	/// <summary>
	/// Scratch session holds information about a particular ProtoScratch session.
	/// </summary>
	public class ScratchSession
	{
		public byte[] key { get; private set; }
		
		public byte vMajor { get; private set; }
		public byte vMinor { get; private set; }
		
		public int port 
		{ 
			get
			{
				return _port;
			}
			set
			{
				if (writeLock) throw new ScratchException(ScratchException.eType.ReadOnly, "Value change attempted on locked session!");
				_port = value;
			} 
		}
		
		public bool useSessionIDs 
		{ 
			get
			{
				return _useSessionIDs;
			}
			set
			{
				if (writeLock) throw new ScratchException(ScratchException.eType.ReadOnly, "Value change attempted on locked session!");
				_useSessionIDs = value;
			}
		}
		
		private RSAParameters _rsaKey;
		public RSAParameters rsaKey
		{
			get
			{
				return _rsaKey;
			}
			set
			{
				if (writeLock) throw new ScratchException(ScratchException.eType.ReadOnly, "Value change attempted on locked session!");
				_rsaKey = value;
			}
		}
		
		private int _port;
		private bool _useSessionIDs = true;
		private bool writeLock;
		private Type creator;
		
		protected ScratchSession(Type creator)
		{
			if (creator.BaseType != typeof(ScratchEvents))
				throw new ScratchException(ScratchException.eType.InvalidOperation, "Type does not implement ScratchEvents!");
			setKey(0);
			this.creator = creator;
		}
		
		public ScratchEvents create()
		{
			return (ScratchEvents)Activator.CreateInstance(creator);
		}
		
		/// <summary>
		/// Locks all data in this session, preventing further changes from being made.
		/// </summary>
		protected void lockSettings()
		{
			writeLock = true;
		}
		
		/// <summary>
		/// Sets the key for this session. The key is this protocol implementations identifier.
		/// </summary>
		/// <param name='Key'>
		/// The key to use.
		/// </param>
		/// <exception cref='ScratchException'>
		/// Is thrown when the operation is attempted on a locked session.
		/// </exception>
		public void setKey(int Key)
		{
			if (writeLock) throw new ScratchException(ScratchException.eType.ReadOnly, "Value change attempted on locked session!");
			Key = IPAddress.HostToNetworkOrder(Key);
			this.key = BitConverter.GetBytes(Key);
		}
		
		/// <summary>
		/// Sets the protocol version.
		/// </summary>
		/// <param name='vMajor'>
		/// The major version number (i.e. 2 in 2.1)
		/// </param>
		/// <param name='vMinor'>
		/// The minor version number (i.e. 1 in 2.1)
		/// </param>
		/// <exception cref='ScratchException'>
		/// Is thrown when the operation is attempted on a locked session.
		/// </exception>
		public void setVersion(byte vMajor, byte vMinor)
		{
			if (writeLock) throw new ScratchException(ScratchException.eType.ReadOnly, "Value change attempted on locked session!");
			this.vMajor = vMajor;
			this.vMinor = vMinor;
		}
	}
}

